/*
 * @Author: liuqiag
 * @Date: 2021-10-01 17:36:07
 * @LastEditTime: 2021-10-02 00:04:38
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \练习\snake\src\moduls\Snake.ts
 */

class Snake {
  // 表示蛇头的元素
  head: HTMLElement;
  bodies: HTMLCollection; // 蛇的身体 包括蛇头
  // 获取蛇容器
  element: HTMLElement;

  constructor() {
    this.element = document.getElementById('snake')!
    this.head = document.querySelector('#snake > div') as HTMLElement;
    this.bodies = this.element.getElementsByTagName('div')
  }

  // 获取蛇头x,y坐标
  get X() {
    return this.head.offsetLeft
  }
  get Y() {
    return this.head.offsetTop
  }

  // 设置蛇头坐标
  set X(val) {
    if(this.X === val) {
      return
    }
    // 判断是否撞墙(就是X的合法范围0~290)
    if(val < 0 || val > 290) {
      // 撞墙了
      throw new Error()
    }

    // 修改X时,是在修改水平坐标,蛇在左右移动,蛇在向左移动时不能向右移动,反之亦然
    if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetLeft === val) {
      // 如果发生了掉头 让蛇向反方向继续走
      if(val > this.X) {
        // 如果新值大于就值,则说明在向右走,应该使蛇继续向左走
        val = this.X - 10
      } else {
        val = this.X + 10
      }
    }

    // 移动身体
    this.moveBody()
    this.head.style.left = val + 'px'
    
    // 检查有没有撞到自己
    this.checkHeadBody()
  } 
  set Y(val) {
    if(this.Y === val) {
      return
    }
    // 判断是否撞墙(就是Y的合法范围0~290)
    if(val < 0 || val > 290) {
      // 撞墙了
      throw new Error()
    }

    // 修改Y时,是在修改垂直坐标,蛇在上下移动,蛇在向上移动时不能向下移动,反之亦然
    if(this.bodies[1] && (this.bodies[1] as HTMLElement).offsetTop === val) {
      // 如果发生了掉头 让蛇向反方向继续走
      if(val > this.Y) {
        // 如果新值大于就值,则说明在向下走,应该使蛇继续向上走
        val = this.Y - 10
      } else {
        val = this.Y + 10
      }
    }

    // 移动身体
    this.moveBody()
    this.head.style.top = val + 'px'

    // 检查有没有撞到自己
    this.checkHeadBody()
  }

  // 设置蛇吃到食物增加生体方法
  addBody() {
    this.element.insertAdjacentHTML("beforeend", "<div></div>")
  }

  // 添加一个身体移动过的方法
  moveBody() {
    /**
     *  将后边的身体位置设置为前一节身体的位置
     *  例子: 4节 = 3节  3节=2节 2节=蛇头
     */    
    const length = this.bodies.length - 1
    for(let i = length; i > 0; i--) {
      // 获取前边身体位置
      let X = (this.bodies[i-1] as HTMLElement).offsetLeft;
      let Y = (this.bodies[i-1] as HTMLElement).offsetTop;

      // 将位置赋值到当前身体
      (this.bodies[i] as HTMLElement).style.left = X + 'px';
      (this.bodies[i] as HTMLElement).style.top = Y + 'px';
    }
  }

  checkHeadBody() {
    // 获取所有的身体,检查是否和蛇头坐标重叠
    const length = this.bodies.length
    for(let i = 1; i < length; i++) {
      const bd = this.bodies[i] as HTMLElement
      if(this.X === bd.offsetLeft && this.Y === bd.offsetTop) {
        throw new Error('撞到自己了')
      }
    }
  }
}

export default Snake